#include "GLSquareWindow.h"

//这篇介绍VAO、VBO、EBO的博客是相当牛逼的(它们三个都是用来操作顶点数据的)
//https://blog.csdn.net/u012861978/article/details/130953012
GLSquareWindow::GLSquareWindow(QWidget* parent)
	: QOpenGLWidget(parent)
{
	this->resize(QSize(480, 480));
	this->setWindowTitle("正方形");
	this->setWindowIcon(QIcon("images/opencv.png"));
	QVBoxLayout* vBoxLayout = new QVBoxLayout(this);
	//设置线框模式
	QHBoxLayout* hLayoutMode = new QHBoxLayout(this);
	QRadioButton* radioLineMode = new QRadioButton(this);
	radioLineMode->setText("线框模式");
	QRadioButton* radioFullMode = new QRadioButton(this);
	radioFullMode->setChecked(true);
	radioFullMode->setText("填充模式");
	hLayoutMode->addWidget(radioLineMode);
	hLayoutMode->addWidget(radioFullMode);
	hLayoutMode->setAlignment(Qt::AlignTop | Qt::AlignLeft);


	QHBoxLayout* hLayout = new QHBoxLayout(this);
	QPushButton* btnRed = new QPushButton(this);
	btnRed->setText("红色");
	QPushButton* btnGreen = new QPushButton(this);
	btnGreen->setText("绿色");
	QPushButton* btnBlue = new QPushButton(this);
	btnBlue->setText("蓝色");
	hLayout->addWidget(btnRed);
	hLayout->addWidget(btnGreen);
	hLayout->addWidget(btnBlue);
	hLayout->setAlignment(Qt::AlignTop);
	vBoxLayout->addLayout(hLayoutMode);
	vBoxLayout->addLayout(hLayout);
	vBoxLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
	connect(btnRed, &QPushButton::clicked, [=]() {
		changeSquareColor(SquareColor::RED2);
		});

	connect(btnGreen, &QPushButton::clicked, [=]() {
		changeSquareColor(SquareColor::GREEN2);
		});

	connect(btnBlue, &QPushButton::clicked, [=]() {
		changeSquareColor(SquareColor::BLUE2);
		});

	connect(radioFullMode, &QRadioButton::clicked, [=]() {
		setPolygonMode(true);
		});

	connect(radioLineMode, &QRadioButton::clicked, [=]() {
		setPolygonMode(false);
		});


}

void GLSquareWindow::initializeGL() {
	this->initializeOpenGLFunctions();
	//设置清屏颜色
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	drawSquare();
}

void GLSquareWindow::resizeGL(int w, int h) {
	glViewport(0, 0, w, h);
}

void GLSquareWindow::paintGL() {
	if (isFullMode) {//切换线框模式
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
	else {
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	//原生绘制
	glUseProgram(programShaderNative);
	//找到ourColor的位置
	GLint colorLocation = glGetUniformLocation(programShaderNative, "ourColor");
	switch (mColor) {
	case SquareColor::RED2:
		glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f);//给ourColor赋值
		break;
	case SquareColor::GREEN2:
		glUniform4f(colorLocation, 0.0f, 1.0f, 0.0f, 1.0f);//给ourColor赋值
		break;
	case SquareColor::BLUE2:
		glUniform4f(colorLocation, 0.0f, 0.0f, 1.0f, 1.0f);//给ourColor赋值
		break;
	}
	glBindVertexArray(VAO);//说明要使用VAO配置的顶点属性及对应的VBO及EBO
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, /*indices*/0);
	//glDrawArrays(GL_TRIANGLES, 0, 3);
}

void GLSquareWindow::changeSquareColor(SquareColor mColor) {
	this->mColor = mColor;
	update();
}

GLSquareWindow::~GLSquareWindow()
{
	//释放VAO、VBO状态
	/*glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glBindVertexArray(0);
	glDeleteProgram(programShaderNative);*/
}

//使用纯gl绘制
void GLSquareWindow::drawSquare() {
	//创建四边形的顶点
	GLfloat vertices[] = {
		// 位置 
		 0.5f,  0.5f, 0.0f,// 右上角
		 0.5f, -0.5f, 0.0f,// 右下角
		-0.5f, -0.5f, 0.0f,// 左下角
		-0.5f,  0.5f, 0.0f, // 左上角
		 //0.0f, -0.5f, 0.0f,  // left
		 //0.9f, -0.5f, 0.0f,  // right
		 //0.45f, 0.5f, 0.0f   // top 
	};

	glGenVertexArrays(1, &VAO);//创建VAO:顶点数组对象
	glGenBuffers(1, &VBO);//创建VBO：顶点数组缓冲

	//绑定VAO和VBO对象
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	
	//把顶点数据放入缓冲区
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//告知显卡如何解析缓冲中的属性
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	//开启VAO管理第一个属性
	glEnableVertexAttribArray(0);

	//创建顶点着色器
	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	QFile vertexShaderFile(":/QtForOpenCV4Tool/shader/square.vert");
	if (!vertexShaderFile.open(QIODevice::ReadOnly)) {
		qDebug() << "Cannot open vertex shader file for reading";
	}
	QString verQStr = vertexShaderFile.readAll();
	std::string verStdStr = verQStr.toStdString();
	const char* vertexStr = verStdStr.c_str();
	qDebug() << "vertexStr-------------" << vertexStr;
	vertexShaderFile.close();
	glShaderSource(vertexShader, 1, &vertexStr, NULL);
	glCompileShader(vertexShader);
	//创建片元着色器
	QFile fragShaderFile(":/QtForOpenCV4Tool/shader/square.frag");
	if (!fragShaderFile.open(QIODevice::ReadOnly)) {
		qDebug() << "Cannot open frag shader file for reading";
	}
	QString fragQStr = fragShaderFile.readAll();
	std::string fragStdStr = fragQStr.toStdString();
	const char* fragmentStr = fragStdStr.c_str();
	qDebug() << "fragmentStr-------------" << fragmentStr;
	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentStr, NULL);
	fragShaderFile.close();
	glCompileShader(fragmentShader);

	//创建program
	programShaderNative = glCreateProgram();
	//将着色器和显卡程序关联
	glAttachShader(programShaderNative, vertexShader);
	glAttachShader(programShaderNative, fragmentShader);
	glLinkProgram(programShaderNative);//链接程序

	//着色器使用后删除掉
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	//EBO创建与绑定
	glGenBuffers(1, &EBO);//EBO元素索引缓冲，用来指定顶点应该如何排列和绘制
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	//释放VAO、VBO状态
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
	glBindVertexArray(0);
}

void GLSquareWindow::setPolygonMode(bool mFullMode) {
	this->isFullMode = mFullMode;
	update();
}
